home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / strategy / blue-2.2 / blue.tar / blue.c < prev    next >
C/C++ Source or Header  |  1995-05-06  |  9KB  |  400 lines

  1. /*****************************************************************************
  2.  *                                                                           *
  3.  *                         B l u e   M o o n                                 *
  4.  *                         =================                                 *
  5.  *                               V2.2b                                        *
  6.  *                   A patience game by T.A.Lister                           *
  7.  *            Integral screen support by Eric S. Raymond                     *
  8.  *                                                                           *
  9.  *****************************************************************************/
  10.  
  11. /*
  12.  * Compile this with the command `cc -O blue.c -lcurses -o blue'. For best
  13.  * results, use the portable freeware ncurses(3) library.  On non-Intel
  14.  * machines, SVr4 curses is just as good.
  15.  */
  16.  
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <unistd.h>
  20. #include <signal.h>
  21. #include <time.h>
  22. #include <curses.h>
  23. #include <term.h>
  24.  
  25. #define NOCARD        (-1)
  26.  
  27. #define ACE        0
  28. #define KING        12
  29. #define SUIT_LENGTH    13
  30.  
  31. #define HEARTS        0
  32. #define SPADES        1
  33. #define DIAMONDS    2
  34. #define CLUBS        3
  35. #define NSUITS        4
  36.  
  37. #define GRID_WIDTH    14    /*    13+1  */
  38. #define GRID_LENGTH    56    /* 4*(13+1) */
  39. #define PACK_SIZE    52
  40.  
  41. #define BASEROW        1
  42. #define PROMPTROW    11
  43.  
  44. static int deck_size = PACK_SIZE;    /* initial deck */
  45. static int deck[PACK_SIZE];
  46.  
  47. static int grid[GRID_LENGTH];    /* card layout grid */
  48. static int freeptr[4];        /* free card space pointers */
  49.  
  50. static int deal_number=0;
  51.  
  52. static char *ranks[SUIT_LENGTH] =
  53.     {" A"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9","10"," J"," Q"," K"};
  54.  
  55. static chtype letters[] =
  56. {
  57.     'h' | COLOR_PAIR(COLOR_RED),    /* hearts */
  58.     's' | COLOR_PAIR(COLOR_GREEN),    /* spades */
  59.     'd' | COLOR_PAIR(COLOR_RED),    /* diamonds */
  60.     'c' | COLOR_PAIR(COLOR_GREEN),    /* clubs */
  61. };
  62.  
  63. #if defined(__i386__) && defined(A_PCCHARSET)
  64. static chtype glyphs[] =
  65. {
  66.     '\003' | A_PCCHARSET | COLOR_PAIR(COLOR_RED),    /* hearts */
  67.     '\006' | A_PCCHARSET | COLOR_PAIR(COLOR_GREEN),    /* spades */
  68.     '\004' | A_PCCHARSET | COLOR_PAIR(COLOR_RED),    /* diamonds */
  69.     '\005' | A_PCCHARSET | COLOR_PAIR(COLOR_GREEN),    /* clubs */
  70. };
  71. #endif /* __i386__ && A_PCCHARSET */
  72.  
  73. static chtype *suits = letters;    /* this may change to glyphs below */
  74.  
  75. static void die(onsig)
  76. int onsig;
  77. {
  78.     signal(onsig, SIG_IGN);
  79.     endwin();
  80.     exit(0);
  81. }
  82.  
  83. static void init_vars()
  84. {
  85.     int i;
  86.  
  87.     deck_size = PACK_SIZE;
  88.     for (i=0; i < PACK_SIZE; i++)
  89.     deck[i]=i;
  90.     for (i = 0; i < 4; i++)
  91.     freeptr[i]=i * GRID_WIDTH;
  92. }
  93.  
  94. static void shuffle(size)
  95. int size;
  96. {
  97.     int i,j,numswaps,swapnum,temp;
  98.  
  99.     numswaps=size*10;        /* an arbitrary figure */
  100.  
  101.     for (swapnum=0;swapnum<numswaps;swapnum++)
  102.     {
  103.     i=rand() % size;
  104.     j=rand() % size;
  105.     temp=deck[i];
  106.     deck[i]=deck[j];
  107.     deck[j]=temp;
  108.     }
  109. }
  110.  
  111. static void deal_cards()
  112. {
  113.     int ptr, card=0, value, csuit, crank, suit, aces[4];
  114.  
  115.     for (suit=HEARTS;suit<=CLUBS;suit++)
  116.     {
  117.     ptr=freeptr[suit];
  118.     grid[ptr++]=NOCARD;    /* 1st card space is blank */
  119.     while ((ptr % GRID_WIDTH) != 0)
  120.     {
  121.         value=deck[card++];
  122.         crank=value % SUIT_LENGTH;
  123.         csuit=value / SUIT_LENGTH;
  124.         if (crank==ACE)
  125.         aces[csuit]=ptr;
  126.         grid[ptr++]=value;
  127.     }
  128.     }
  129.  
  130.     if (deal_number==1)        /* shift the aces down to the 1st column */
  131.     for (suit=HEARTS;suit<=CLUBS;suit++)
  132.     {
  133.         grid[suit * GRID_WIDTH] = suit * SUIT_LENGTH;
  134.         grid[aces[suit]]=NOCARD;
  135.         freeptr[suit]=aces[suit];
  136.     }
  137. }
  138.  
  139. static void printcard(value)
  140. int value;
  141. {
  142.     (void) addch(' ');
  143.     if (value == NOCARD)
  144.     (void) addstr("   ");
  145.     else
  146.     {
  147.     addch(ranks[value % SUIT_LENGTH][0] | COLOR_PAIR(COLOR_BLUE));
  148.     addch(ranks[value % SUIT_LENGTH][1] | COLOR_PAIR(COLOR_BLUE));
  149.     addch(suits[value / SUIT_LENGTH]);
  150.     }
  151.     (void) addch(' ');
  152. }
  153.  
  154. static void display_cards(deal)
  155. int deal;
  156. {
  157.     int row, card;
  158.  
  159.     clear();
  160.     (void)printw(
  161.          "Blue Moon 2.1 - by Tim Lister & Eric Raymond - Deal %d.\n",
  162.          deal);
  163.     for(row=HEARTS;row<=CLUBS;row++)
  164.     {
  165.     move(BASEROW + row + row + 2, 1);
  166.     for(card=0;card<GRID_WIDTH;card++)
  167.         printcard(grid[row * GRID_WIDTH + card]);
  168.     }
  169.  
  170.     move(PROMPTROW + 2, 0); refresh();
  171. #define P(x)    (void)printw("%s\n", x)
  172. P("   This 52-card solitaire starts with  the entire deck shuffled and dealt");
  173. P("out in four rows.  The aces are then moved to the left end of the layout,");
  174. P("making 4 initial free spaces.  You may move to a space only the card that");
  175. P("matches the left neighbor in suit, and is one greater in rank.  Kings are");
  176. P("high, so no cards may be placed to their right (they create dead spaces).");
  177. P("  When no moves can be made,  cards still out of sequence are  reshuffled");
  178. P("and dealt face up after the ends of the partial sequences, leaving a card");
  179. P("space after each sequence, so that each row looks like a partial sequence");
  180. P("followed by a space, followed by enough cards to make a row of 14.       ");
  181. P("  A moment's reflection will show that this game cannot take more than 13");
  182. P("deals. A good score is 1-3 deals, 4-7 is average, 8 or more is poor.     ");
  183. #undef P
  184.     refresh();
  185. }
  186.  
  187. static int find(card)
  188. int card;
  189. {
  190.     int i;
  191.  
  192.     if ((card<0) || (card>=PACK_SIZE))
  193.     return(NOCARD);
  194.     for(i = 0; i < GRID_LENGTH; i++)
  195.     if (grid[i] == card)
  196.         return i;
  197.     return(NOCARD);
  198. }
  199.  
  200. static void movecard(src, dst)
  201. int src, dst;
  202. {
  203.     grid[dst]=grid[src];
  204.     grid[src]=NOCARD;
  205.  
  206.     move( BASEROW + (dst / GRID_WIDTH)*2+2, (dst % GRID_WIDTH)*5 + 1);
  207.     printcard(grid[dst]);
  208.  
  209.     move( BASEROW + (src / GRID_WIDTH)*2+2, (src % GRID_WIDTH)*5 + 1);
  210.     printcard(grid[src]);
  211.  
  212.     refresh();
  213. }
  214.  
  215. static void play_game()
  216. {
  217.     int dead=0, i, j;
  218.     char c;
  219.     int select[4], card;
  220.  
  221.     while (dead<4)
  222.     {
  223.     dead=0;
  224.     for (i=0;i<4;i++)
  225.     {
  226.         card=grid[freeptr[i]-1];
  227.  
  228.         if (    ((card % SUIT_LENGTH)==KING)
  229.         ||
  230.         (card==NOCARD)    )
  231.         select[i]=NOCARD;
  232.         else
  233.         select[i]=find(card+1);
  234.  
  235.         if (select[i]==NOCARD)
  236.         dead++;
  237.     };
  238.  
  239.     if (dead < 4)
  240.     {
  241.         char    live[NSUITS], *lp = live;
  242.  
  243.         for (i=0;i<4;i++)
  244.         {
  245.         if (select[i] != NOCARD)
  246.         {
  247.             move(BASEROW + (select[i] / GRID_WIDTH)*2+3,
  248.              (select[i] % GRID_WIDTH)*5);
  249.             (void)printw("   %c ", *lp++ = 'a' + i);
  250.         }
  251.         };
  252.         *lp = '\0';
  253.  
  254.         if (strlen(live) == 1)
  255.         {
  256.         move(PROMPTROW,0);
  257.         (void)printw(
  258.             "Making forced moves...                                 ");
  259.         refresh();
  260.         (void) sleep(1);
  261.         c = live[0];
  262.         }
  263.         else
  264.         {
  265.         char    buf[BUFSIZ];
  266.  
  267.         (void)sprintf(buf,
  268.             "Type [%s] to move, r to redraw, q or INTR to quit: ",
  269.             live);
  270.  
  271.         do {
  272.             move(PROMPTROW,0);
  273.             (void) addstr(buf);
  274.             move(PROMPTROW, strlen(buf));
  275.             clrtoeol();
  276.             (void) addch(' ');
  277.         } while
  278.             (((c = getch())<'a' || c>'d') && (c!='r') && (c!='q'));
  279.         }
  280.  
  281.         for (j = 0; j < 4; j++)
  282.         if (select[j]!=NOCARD)
  283.         {
  284.             move(BASEROW + (select[j] / GRID_WIDTH)*2+3,
  285.              (select[j] % GRID_WIDTH)*5);
  286.             (void)printw("     ");
  287.         }
  288.  
  289.         if (c == 'r')
  290.         display_cards(deal_number);
  291.         else if (c == 'q')
  292.         die(0);
  293.         else
  294.         {
  295.         i = c-'a';
  296.         if (select[i] == NOCARD)
  297.             beep();
  298.         else
  299.         {
  300.             movecard(select[i], freeptr[i]);
  301.             freeptr[i]=select[i];
  302.         }
  303.         }
  304.     }
  305.     }
  306.  
  307.     move(PROMPTROW, 0);
  308.     standout();
  309.     (void)printw("Finished deal %d - type any character to continue...", deal_number);
  310.     standend();
  311.     (void) getch();
  312. }
  313.  
  314. static int collect_discards()
  315. {
  316.     int row, col, cardno=0, finish, gridno;
  317.  
  318.     for (row=HEARTS;row<=CLUBS;row++)
  319.     {
  320.     finish=0;
  321.     for (col=1;col<GRID_WIDTH;col++)
  322.     {
  323.         gridno=row * GRID_WIDTH + col;
  324.  
  325.         if ((grid[gridno]!=(grid[gridno-1]+1))&&(finish==0))
  326.         {
  327.         finish=1;
  328.         freeptr[row]=gridno;
  329.         };
  330.  
  331.         if ((finish!=0)&&(grid[gridno]!=NOCARD))
  332.         deck[cardno++]=grid[gridno];
  333.     }
  334.     }
  335.     return cardno;
  336. }
  337.  
  338. static void game_finished(deal)
  339. int deal;
  340. {
  341.     clear();
  342.     (void)printw("You finished the game in %d deals. This is ",deal);
  343.     standout();
  344.     if (deal<2)
  345.     (void)addstr("excellent");
  346.     else if (deal<4)
  347.     (void)addstr("good");
  348.     else if (deal<8)
  349.     (void)addstr("average");
  350.     else
  351.     (void)addstr("poor");
  352.     standend();
  353.     (void) addstr(".         ");
  354.     refresh();
  355. }
  356.  
  357. main(int argc, char *argv[])
  358. {
  359.     (void) signal(SIGINT, die);
  360.     initscr();
  361.  
  362.     /*
  363.      * We use COLOR_GREEN because COLOR_BLACK is wired to the wrong thing.
  364.      */
  365.     start_color();
  366.     init_pair(COLOR_RED,     COLOR_RED,   COLOR_WHITE);
  367.     init_pair(COLOR_BLUE,    COLOR_BLUE,  COLOR_WHITE);
  368.     init_pair(COLOR_GREEN,   COLOR_BLACK, COLOR_WHITE);
  369.  
  370. #if defined(__i386__) && defined(A_PCCHARSET)
  371.     if (tigetstr("smpch"))
  372.     suits = glyphs;
  373. #endif /* __i386__ && A_PCCHARSET */
  374.  
  375.     cbreak();
  376.  
  377.     if (argc == 2)
  378.     srand(atoi(argv[1]));
  379.     else
  380.     srand((int)time((long *)0));
  381.  
  382.     init_vars();
  383.  
  384.     do{
  385.     deal_number++;
  386.     shuffle(deck_size);
  387.     deal_cards();
  388.     display_cards(deal_number);
  389.     play_game();
  390.     }
  391.     while
  392.     ((deck_size=collect_discards()) != 0);
  393.  
  394.     game_finished(deal_number);
  395.  
  396.     die(0);
  397. }
  398.  
  399. /* blue.c ends here */
  400.